package indexer;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

public class ReverseIndex {
	private Hashtable<String,IndexTerm> lookupTable;
	private Integer numOfFile;
	private Integer nextFileNo;
	private Hashtable<String,Integer> fileNameTable;
	protected static final String FILENAMEFORFILETABLE=new String ("fileNameTable.txt");
	protected static final String FILENAMEFORREVERSEINDEX=new String ("reverseIndex.txt");
	
	public ReverseIndex (){
		lookupTable=new Hashtable<String,IndexTerm>();
		numOfFile=new Integer(0);
		nextFileNo=new Integer(0);
		fileNameTable=new Hashtable<String,Integer>();
		
	}
	public ReverseIndex (int initialCap){
		lookupTable=new Hashtable<String,IndexTerm>(initialCap);
		numOfFile=new Integer(0);
		nextFileNo=new Integer(0);
		fileNameTable=new Hashtable<String,Integer>();
	}
	public ReverseIndex (int initialCap,float loadFac){
		lookupTable=new Hashtable<String,IndexTerm>(initialCap,loadFac);
		numOfFile=new Integer(0);
		nextFileNo=new Integer(0);
		fileNameTable=new Hashtable<String,Integer>();
	}
	
	public void indexFile(String fileName)throws IOException{
		File file=new File(fileName);
		if (!file.exists()){
			System.out.println("Warning message from ReverseIndex: \n"
					+ "the file to index: " + fileName + "does not exist");
			return;
		}
		String totalName=file.getAbsolutePath();
		if (fileNameTable.containsKey(totalName)){
			System.out.println("Warning Message from ReverseIndex: \n" + 
					"the file to index: " + totalName + "is already indexed");
			return;
		}
		int currentFile=nextFileNo++;
		numOfFile++;
		fileNameTable.put(totalName,currentFile);
		
		/*TextFileReader tfr=new TextFileReader(fileName);
		tfr.getWords();
		tfr.standardize();*/
		TextFileSegmentor tfs=new TextFileSegmentor(fileName);
		Vector<WordUnit> vec=tfs.turnToWordUnits();
		//above changed by shitgao 0:24 06/23/08
		
		Enumeration<WordUnit> words=vec.elements();
		
		WordUnit aWord;
		while (words.hasMoreElements()){
			aWord=words.nextElement();
			addWordTerm(aWord.aString,currentFile,aWord.offSet);
		}
		
		System.out.println("the file: "+ file.getAbsolutePath()+" is indexed");
	}
	
	protected void addWordTerm(String word,int fSN,int pos){
		if (word==null){
			return;
		}
		if (!lookupTable.containsKey(word)){
			IndexTerm it=new IndexTerm();
			it.addpos(fSN, pos);
			lookupTable.put(word, it);
		}
		else{
			lookupTable.get(word).addpos(fSN, pos);
		}
	}
	
	public Boolean isFileIndexed(String fileName){
		File file=new File(fileName);
		return fileNameTable.containsKey(file.getAbsolutePath());
	}
	
	public void indexDirectory(String dirName,boolean isRecursive)
		throws IOException{
		File dir=new File(dirName);
		if (!(dir.exists()&&dir.isDirectory())){
			System.out.println("Waring message from RverseIndex: " +
					"The directory to index doesn\'t exist or isn\'t a directory");
			return;
		}
		File tempfile;
		String [] fileNames=dir.list();
		for (int i=0;i<fileNames.length;i++){
			tempfile=new File (dir.getAbsolutePath()+File.separator+fileNames[i]);
			//System.out.println(tempfile.getAbsolutePath());
			if (tempfile.isFile())
				indexFile(tempfile.getAbsolutePath());
			else{
				if (isRecursive)
					indexDirectory(tempfile.getAbsolutePath(),true);
			}
		}
		System.out.println("The directory: "+dir.getAbsolutePath()+" is indexed");
	}
	
	public void deleteFile(String fileName) throws IOException{
		File file=new File(fileName);
		if (!fileNameTable.containsKey(file.getAbsolutePath())){
			System.out.println("Warning message from ReverseIndex: " +
					"the file to delete: \n"+file.getAbsolutePath()+" is not indexed");
			return;
		}
		int fileNo=fileNameTable.get(file.getAbsolutePath());
		/*TextFileReader tfr=new TextFileReader(file.getAbsolutePath());
		tfr.getWords();
		tfr.standardize();*/
		Vector<WordUnit> vec=new TextFileSegmentor(file.getAbsolutePath()).turnToWordUnits();
		Enumeration<WordUnit> en=vec.elements();
		WordUnit wu;
		//above changed by shitgao 0:26 6/23/08
		
		while (en.hasMoreElements()){
			wu=en.nextElement();
			if (wu.aString!=null && lookupTable.get(wu.aString).containsFile(fileNo))
				lookupTable.get(wu.aString).deletedoc(fileNo);
		}
		numOfFile--;
		fileNameTable.remove(file.getAbsolutePath());
		System.out.println("file: "+file.getAbsolutePath()+" is deleted from the index");
	}
	
	public void deleteDirectory(String dirName,boolean isRecursive)
		throws IOException{
		File dir=new File(dirName);
		if (!(dir.exists()&&dir.isDirectory())){
			System.out.println("Waring message from RverseIndex: " +
					"The directory to delete doesn\'t exist or isn\'t a directory");
			return;
		}
		File tempfile;
		String tempstr;
		String [] fileNames=dir.list();
		for (int i=0;i<fileNames.length;i++){
			tempfile=new File (dir.getAbsolutePath()+"\\"+fileNames[i]);
			tempstr=tempfile.getAbsolutePath();
			if ((tempfile.isFile()) && (fileNameTable.containsKey(tempstr)))
				deleteFile(tempstr);
			else if (isRecursive)
				deleteDirectory(tempstr,true);
		}
		System.out.println("the directory: "+dir.getAbsolutePath()+" is deleted from the index");
	}
	
	public void reindexFile(String fileName) throws IOException{
		File file=new File(fileName);
		if (fileNameTable.containsKey(file.getAbsolutePath())){
			deleteFile(file.getAbsolutePath());
			indexFile(file.getAbsolutePath());
		}
		else{
			indexFile(file.getAbsolutePath());
		}
	}
	
	public void reindexDirectory(String dirName,boolean isRecursive)
		throws IOException{
		File dir=new File(dirName);
		if (!(dir.exists()&&dir.isDirectory())){
			System.out.println("Waring message from RverseIndex: " +
					"The directory to reindex doesn\'t exist or isn\'t a directory");
			return;
		}
		File tempfile;
		String [] fileNames=dir.list();
		for (int i=0;i<fileNames.length;i++){
			tempfile=new File (dir.getAbsolutePath()+"\\"+fileNames[i]);
			if (tempfile.isFile())
				reindexFile(tempfile.getAbsolutePath());
			else if (isRecursive) reindexFile(tempfile.getAbsolutePath());
		}
		System.out.println("The directory: "+dir.getAbsolutePath()+" is reindexed");
	}
	
	public Vector<Integer> filesContainsWord(String word){
		if (lookupTable.containsKey(word)){
			return lookupTable.get(word).returnfileSN();
		}
		else{
			return null;
		}
	}
	
	public Vector<Integer> positionsWordAppear(String word,int fSN){
		if (lookupTable.containsKey(word) && 
				lookupTable.get(word).containsFile(fSN)){
			return lookupTable.get(word).returnpos(fSN);
		}
		else{
			return null;
		}
	}
	
	public String queryFileSN (int fSN){
		if (fileNameTable.containsValue(fSN)){
			Enumeration<String> en=fileNameTable.keys();
			String tempstr=new String();
			while(en.hasMoreElements()){
				tempstr=en.nextElement();
				if (fileNameTable.get(tempstr)==fSN)
					break;	
			}
			return tempstr;
		}
		else{
			System.out.println("Warning message from ReverseIndex: \n"
					+ "the fileSN to query " + fSN + " does not exist");
			return null;
		}
	}
	
	public void storeIndex (String dirName) throws IOException{
		File dir=new File(dirName);
		if (!(dir.exists()&&dir.isDirectory())){
			System.out.println("Warning message from ReverseIndex: \n"
					+ "the directory to store index does not exist");
			System.out.println("Rewriting...");
			dir.mkdirs();
		}
		File ffn=new File(dir.getAbsolutePath() + File.separator + FILENAMEFORFILETABLE);
		if (!ffn.exists()){
			ffn.createNewFile();
		}else{
			ffn.delete();
			ffn.createNewFile();
		}
		BufferedWriter bw;
		try{
			bw=new BufferedWriter(new FileWriter(ffn));
		}catch (FileNotFoundException fnfe){
			System.out.println("Warning message from ReverseIndex: \n"
					+ "can not open file: " + ffn.getAbsolutePath());
			return;
		}
		bw.write(numOfFile.toString());
		bw.newLine();
		bw.write(nextFileNo.toString());
		bw.newLine();
		Enumeration<String> fileNames=fileNameTable.keys();
		String tempstr;
		Integer tempint;
		while (fileNames.hasMoreElements()){
			tempstr=fileNames.nextElement();
			tempint=fileNameTable.get(tempstr);
			bw.write(tempstr);
			bw.newLine();
			bw.write(tempint.toString());
			bw.newLine();
		}
		bw.close();
		System.out.println("The file name table is stored to \n" + 
				ffn.getAbsolutePath());
		File fri= new File(dir.getAbsolutePath() + File.separator + FILENAMEFORREVERSEINDEX);
		if (!fri.exists()){
			fri.createNewFile();
		}else{
			fri.delete();
			fri.createNewFile();
		}
		try{
			bw=new BufferedWriter(new FileWriter(fri));
		}catch (FileNotFoundException fnfe){
			System.out.println("Warning message from ReverseIndex: \n"
					+ "can not open file: " + fri.getAbsolutePath());
			return;
		}
		Enumeration<String> words=lookupTable.keys();
		Enumeration<Integer> fileSN;
		while (words.hasMoreElements()){
			tempstr=words.nextElement();
			bw.write(tempstr);
			bw.newLine();
			IndexTerm it=lookupTable.get(tempstr);
			bw.write(it.returnNumberOfFile().toString());
			bw.newLine();
			fileSN=it.returnfileSN().elements();
			while (fileSN.hasMoreElements()){
				tempint=fileSN.nextElement();
				bw.write(tempint.toString());
				bw.newLine();
				bw.write(it.returnpos(tempint).toString());
				bw.newLine();
			}
		}
		bw.close();
		System.out.println("The reverse index table is stored to \n" + 
				fri.getAbsolutePath());
	}
	
	public void loadIndex(String dirName) throws IOException{
		lookupTable=new Hashtable<String,IndexTerm>();
		numOfFile=new Integer(0);
		nextFileNo=new Integer(0);
		fileNameTable=new Hashtable<String,Integer>();
		File dir=new File(dirName);
		File ffn=new File(dir.getAbsolutePath()+File.separator+FILENAMEFORFILETABLE);
		File fri=new File(dir.getAbsolutePath()+File.separator+FILENAMEFORREVERSEINDEX);
		if (!ffn.exists()){
			System.out.println("Warning message from ReverseIndex: \n"
					+"the file-name-table file does not exist");
			return;
		}
		if (!fri.exists()){
			System.out.println("Warning message from ReverseIndex: \n"
					+"the reverse index file does not exist");
			return;
		}
		BufferedReader br;
		try{
			br=new BufferedReader(new FileReader(ffn));
		}catch (FileNotFoundException fnfe){
			System.out.println("Warning message from ReverseIndex: \n"
					+"the file-name-table file can not open");
			return;
		}
		numOfFile=new Integer(br.readLine());
		nextFileNo=new Integer(br.readLine());
		String tempstr=br.readLine();
		while (tempstr!=null){
			fileNameTable.put(tempstr, new Integer(br.readLine()));
			tempstr=br.readLine();
		}
		br.close();
		try{
			br=new BufferedReader(new InputStreamReader(new FileInputStream(fri), "utf-8"));
		}catch (FileNotFoundException fnfe){
			System.out.println("Warning message from ReverseIndex: \n"
					+"the reverse-index file can not open");
			return;
		}
		IndexTerm it;
		Vector<Integer> pos;
		StringTokenizer st;
		tempstr=br.readLine();
		while(tempstr!=null){
			it=new IndexTerm();
			lookupTable.put(tempstr, it);
			Integer iter=new Integer(br.readLine());
			for (int i=0; i<iter;i++){
				it.adddoc(new Integer(br.readLine()));
				st=new StringTokenizer(br.readLine(),"[] ,\t\n\r\f");
				pos=new Vector<Integer>();
				while (st.hasMoreTokens()){
					pos.add(new Integer(st.nextToken()));
				}
				it.addpos(pos);
			}
			tempstr=br.readLine();
		}
		System.out.println("the reverse index as well " +
				"as the file-name-table is loaded successfully");
	}
}
